<?php


namespace Um\WechatPay;

use Ke\Utils\CurlRequest;

class PayV3Request extends CurlRequest
{

	private $merchantId = '';

	private $serialNo = '';

	private $privateKey = null;

	private $timestamp = 0;

	private $nonceStr = '';

	public function __destruct()
	{
		if ($this->privateKey !== null) {
			if (is_resource($this->privateKey))
				openssl_free_key($this->privateKey);
		}
	}

	public function isSend()
	{
		return $this->isSend;
	}

	public function setMerchantId(string $id)
	{
		$this->merchantId = $id;
		return $this;
	}

	public function getMerchantId()
	{
		return $this->merchantId;
	}

	public function getSerialNo(): string
	{
		return $this->serialNo;
	}

	public function setSerialNo(string $serialNo)
	{
		$this->serialNo = $serialNo;
		return $this;
	}

	public function setPrivateKeyFile(string $path, string $passphrase = '')
	{
		if ($this->privateKey === null) {
			if (!is_file($path))
				throw new PayException('无效的 Private Key 路径');
			$this->privateKey = file_get_contents($path);
		}
		return $this;
	}

	public function setPrivateKey(string $content)
	{
		$this->privateKey = $content;
		return $this;
	}

	public function hasPrivateKey()
	{
		return !empty($this->privateKey);
	}

	public function mkNonceStr()
	{
		$items = [
			mt_rand(100000, 999999),
			mt_rand(100000, 999999),
			mt_rand(100000, 999999),
			mt_rand(100000, 999999),
			microtime(true),
		];
		return md5(implode('-', $items));
	}

	public function prepare()
	{
		if (empty($this->timestamp))
			$this->timestamp = time() . '';
		if (empty($this->nonceStr))
			$this->nonceStr = $this->mkNonceStr();

		return $this;
	}

	public function setDebugSend(bool $isDebug)
	{
		$this->isDebugSend = $isDebug;
		return $this;
	}

	public function setUri($uri)
	{
		parent::setUri($uri); // TODO: Change the autogenerated stub
		$this->uri->setIgnoreEndSlash(true);
		return $this;
	}

	public function getCanonicalUrl(): string
	{
		return $this->getUri()->toUri(false);
	}

	public function getMethodUpper()
	{
		return mb_strtoupper($this->getMethod());
	}

	protected function mkSignMessage()
	{
		$this->prepare();
		return implode("\n", [
			$this->getMethodUpper(),
			$this->getCanonicalUrl(),
			$this->timestamp,
			$this->nonceStr,
			$this->getBody(),
			'',
		]);
	}

	protected function sign()
	{
		if ($this->privateKey === null)
			throw new PayException('未指定 Private Key');
		$message = $this->mkSignMessage();
		openssl_sign($message, $rawSign, $this->privateKey, 'sha256WithRSAEncryption');
		$sign = base64_encode($rawSign);
		return $sign;
	}

	protected function mkAuthorizationToken()
	{
		if (empty($this->merchantId))
			throw new PayException('未指定商户ID（MchId）');
		if (empty($this->serialNo))
			throw new PayException('未指定商户序列号（SerialNo）');
		$sign = $this->sign();
		$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
			$this->merchantId, $this->nonceStr, $this->timestamp, $this->serialNo, $sign);
		return $token;
	}

	public function getAuthorizationSchema()
	{
		return 'WECHATPAY2-SHA256-RSA2048';
	}

	public function getBody()
	{
		return $this->options[CURLOPT_POSTFIELDS] ?? '';
	}

	protected function mkAuthorization()
	{
		return "{$this->getAuthorizationSchema()} {$this->mkAuthorizationToken()}";
	}

	public function post(array $data = null, string $postBodyType = self::POST_JSON)
	{
		return parent::post($data, $postBodyType); // TODO: Change the autogenerated stub
	}

	protected function beforeSend()
	{
		$auth = $this->mkAuthorization();
		if (!isset($this->options[CURLOPT_HTTPHEADER]))
			$this->options[CURLOPT_HTTPHEADER] = [];
		$this->options[CURLOPT_HTTPHEADER][] = 'Authorization: ' . $auth;
	}

	public function makeOptions()
	{
		return parent::makeOptions(); // TODO: Change the autogenerated stub
	}

	protected function afterSend()
	{
		// @todo 这里应该要校验 response 的内容和头部状态
		// @see https://wechatpay-api.gitbook.io/wechatpay-api-v3/wei-xin-zhi-fu-api-v3-jie-kou-gui-fan
		// @see https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-yan-zheng
	}
}